package cube;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;

public class MyCube {

	private String lutFile;
	private String srcFile;
	private String destFile;
	private int n = 32;

	private ArrayList<ArrayList<Float>> rgbFloatCube = new ArrayList<>();

	private MyCube() {

	}

	public static MyCube Build() {
		return new MyCube();
	}

	public MyCube setLutFile(String lutFile) {
		this.lutFile = lutFile;
		return this;
	}

	public MyCube setSrcFile(String srcFile) {
		this.srcFile = srcFile;
		return this;
	}

	public MyCube setDestFile(String destFile) {
		this.destFile = destFile;
		return this;
	}

	public void doFilter() {
		System.out.println("开始渲染");
		try {
			long t = System.currentTimeMillis();
			BufferedImage bufferedImage = ImageIO.read(new File(srcFile));
			int tType = bufferedImage.getType();
			if (0 == tType) {
				tType = 5;
			}
			BufferedImage grayImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), tType);

			for (int i = 0; i < bufferedImage.getWidth(); i++) {
				for (int j = 0; j < bufferedImage.getHeight(); j++) {
					final int color = bufferedImage.getRGB(i, j);
					final int r = (color >> 16) & 0xff;
					final int g = (color >> 8) & 0xff;
					final int b = color & 0xff;

					float red = r / 255.0f * (n - 1);
					float green = g / 255.0f * (n - 1);
					float blue = b / 255.0f * (n - 1);

					int redH = (int) Math.ceil(red);
					int redL = (int) Math.floor(red);

					int greenH = (int) Math.ceil(green);
					int greenL = (int) Math.floor(green);

					int blueH = (int) Math.ceil(blue);
					int blueL = (int) Math.floor(blue);

					int indexH = cubeIndex(redH, greenH, blueH);
					int indexL = cubeIndex(redL, greenL, blueL);

					ArrayList<Float> toColorH = rgbFloatCube.get(indexH);
					ArrayList<Float> toColorL = rgbFloatCube.get(indexL);

					float toR = mix(toColorL.get(0), toColorH.get(0), red);
					float toG = mix(toColorL.get(1), toColorH.get(1), green);
					float toB = mix(toColorL.get(2), toColorH.get(2), blue);

					int newPixel = colorToRGB(255, (int) (toR * 255), (int) (toG * 255), (int) (toB * 255));
					grayImage.setRGB(i, j, newPixel);
				}
			}

			File newFile = new File(destFile);
			ImageIO.write(grayImage, "jpg", newFile);

			System.out.println(" 耗时 - " + (System.currentTimeMillis() - t));
		} catch (Exception e) {
			e.printStackTrace();
		}

		System.out.println("结束渲染");
	}

	public MyCube initCube() {
		File file = new File(lutFile);
		BufferedReader reader = null;
		try {
			System.out.println("读取lut文件");
			reader = new BufferedReader(new FileReader(file));
			String l = null;
			int line = 1;
			// 一次读入一行，直到读入null为文件结束
			boolean cubeDataStart = false;
			ArrayList<Float> rgb = new ArrayList<>();

			while ((l = reader.readLine()) != null) {
				// 显示行号
				if (cubeDataStart) {
					if(l==null || l.trim().length()==0 || l.startsWith("#")) {
						continue;
					}

					String[] rgbStr = l.split(" ");
					if (rgbStr.length == 3) {
						rgb = new ArrayList<>();
						rgb.add(Float.parseFloat(rgbStr[0]));
						rgb.add(Float.parseFloat(rgbStr[1]));
						rgb.add(Float.parseFloat(rgbStr[2]));
						rgbFloatCube.add(rgb);
					}
				}

//				if (l.startsWith("#LUT data points")) {
//					cubeDataStart = true;
//				}
				
				if (l.startsWith("LUT_3D_SIZE")) {
					cubeDataStart = true;
					String[] numStr = l.split(" ");
					n = Integer.parseInt(numStr[1]);
					System.out.println("读取lut文件 n = " + n);
				}
				
				line++;
			}
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e1) {
				}
			}
		}
		return this;
	}

	private float mix(float a, float b, float c) {
		return (float) (a + (b - a) * (c - Math.floor(c)));
	}

	private int cubeIndex(int r, int g, int b) {
		return r + g * n + b * n * n;
	}

	private int colorToRGB(int alpha, int red, int green, int blue) {

		int newPixel = 0;
		newPixel += alpha;
		newPixel = newPixel << 8;
		newPixel += red;
		newPixel = newPixel << 8;
		newPixel += green;
		newPixel = newPixel << 8;
		newPixel += blue;

		return newPixel;
	}

}
